package com.aizuda.boot.modules.business.contract.controller;

import com.aizuda.boot.modules.business.contract.dto.SingleResponse;
import com.aizuda.boot.modules.business.contract.entity.dto.*;
import com.aizuda.boot.modules.common.constant.enums.ContractStatusEnum;
import com.aizuda.boot.modules.business.contract.entity.vo.*;

import com.aizuda.boot.modules.business.contract.service.ContractService;
import com.aizuda.boot.modules.business.contract.service.ContractExportService;
import com.aizuda.boot.modules.business.log.annotation.Logging;
import com.aizuda.boot.modules.common.constant.enums.LogTypeEnum;
import com.aizuda.boot.modules.business.contract.entity.ContractTypeEntity;
import com.aizuda.boot.modules.business.contract.entity.ContractEntity;
import com.aizuda.boot.modules.flw.flow.FlowTaskAccessStrategy;
import com.aizuda.boot.modules.flw.entity.dto.NextNodesDTO;
import com.aizuda.boot.modules.flw.entity.dto.ProcessInfoDTO;
import com.aizuda.boot.modules.flw.entity.vo.TaskApprovalVO;
import com.aizuda.boot.modules.flw.service.IFlwProcessTaskService;
import com.aizuda.boot.modules.flw.service.IFlwProcessFormService;
import com.aizuda.boot.modules.flw.entity.FlwProcessForm;
import com.aizuda.bpm.engine.FlowLongEngine;
import com.aizuda.bpm.engine.entity.FlwTask;
import com.aizuda.bpm.engine.entity.FlwInstance;
import com.aizuda.bpm.engine.entity.FlwHisInstance;
import com.aizuda.bpm.engine.entity.FlwTaskActor;
import com.aizuda.service.web.UserSession;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author yangshen
 * @version 1.0
 * @date 2025/5/21
 * 合同管理控制器
 *
 * @Author sangyirong
 * @ClassName ContractController
 * @Version 1.0
 * @Date 2025/5/20 13:36
 */
@Slf4j
@RestController
@RequestMapping("/contract")
@Tag(name = "合同管理接口")
public class ContractController {
    @Resource
    private ContractService contractService;
    
    @Resource
    private com.aizuda.boot.modules.business.contract.service.impl.ContractServiceOptimized contractServiceOptimized;

    @Resource
    private IFlwProcessTaskService flwProcessTaskService;

    @Resource
    private IFlwProcessFormService flwProcessFormService;

    @Resource
    private FlowLongEngine flowLongEngine;

    @Resource
    private ContractExportService contractExportService;

    /**
     * 全部合同管理列表查询 - 优化版本
     * 解决N+1查询问题，大幅提升查询性能
     * @param dto
     * @return
     */
    @Operation(summary = "合同管理列表查询")
    @PostMapping("/list")
    public SingleResponse<Page<ContractDTO> > getContractList(@RequestBody ContractListReqDTO dto) {
        // 使用优化后的查询方法，解决性能问题
        // 返回结构与my-contracts接口一致，但contract/list接口不包含arrivalTime字段
        Page<ContractDTO> contractList = contractServiceOptimized.getOptimizedContractList(dto);
        return SingleResponse.of(contractList);
    }


    @GetMapping("/{contractId}")
    @Operation(summary = "获取合同详情")
    @Logging(logType = LogTypeEnum.CONTRACT_WATCH)
    public SingleResponse<ContractDTO> getContractDetail(
            @PathVariable @Parameter(description = "合同ID") Integer contractId
    ) {
        return SingleResponse.of(contractService.getContractDetail(contractId));
    }
    /**
     * 新增合同
     * @param dto
     * @return
     */
    @Operation(summary = "保存合同")
    @PostMapping("/add")
    @Logging(logType = LogTypeEnum.CONTRACT_SAVE)
    public SingleResponse<ContractDTO> addContract(@RequestBody ContractAddReqDTO dto) {
        ContractDTO contractDetail = contractService.saevAndSubmitContract(dto);
        return SingleResponse.of(contractDetail);
    }

    @PostMapping("/update")
    @Operation(summary = "修改合同信息或提交审批")
    @Logging(logType = LogTypeEnum.CONTRACT_UPDATE)
    public SingleResponse updateContract(@RequestBody @Validated ContractUpdateReqDTO dto) {
        contractService.updateContract(dto);

        // 如果传了isSubmit=true，启动审批流程
        if (Boolean.TRUE.equals(dto.getIsSubmit())) {
            try {
                contractService.submitContractForApproval(dto.getBasicInfo().getId());
            } catch (Exception e) {
                // 审批流程启动失败，但合同已经保存，返回错误信息
                throw new RuntimeException("合同修改成功，但启动审批流程失败: " + e.getMessage());
            }
        }

        return SingleResponse.success();
    }


    /**
     *复制合同
     * @param contractId
     * @return
     */
    @Operation(summary = "复制合同")
    @GetMapping("/copy/{contractId}")
    @Logging(logType = LogTypeEnum.CONTRACT_COPY)
    public SingleResponse<Integer> copyContract(@PathVariable Integer contractId) {
        return SingleResponse.of(contractService.copyContract(contractId));
    }




    /**
     * 主合同文本信息
     * @param dto
     * @return
     */
    @Operation(summary = "主合同文本信息")
    @PostMapping("/mainContractText")
    public SingleResponse<ContractTextRespDTO> getMainContractText(@RequestBody CopyContractReqDTO dto) {
        return SingleResponse.of(new ContractTextRespDTO());
    }

    /**
     * 附件合同文本信息
     * @param dto
     * @return
     */
    @Operation(summary = "附件合同文本信息")
    @PostMapping("/appendixContractText")
    public SingleResponse<ContractTextRespDTO> getAppendixContractText(@RequestBody CopyContractReqDTO dto) {
        return SingleResponse.of(new ContractTextRespDTO());
    }


    /**
     * 删除草稿
     * @param contractIds
     * @return
     */
    @Operation (summary = "删除草稿")
    @PostMapping("/delete")
    public SingleResponse deleteDraftContracts(@RequestBody List<Long> contractIds) {
        contractService.deleteDraftContracts(contractIds);
        return SingleResponse.success();
    }


    @GetMapping("/all")
    @Operation(summary = "获取所有合同类型（树形结构）")
    public SingleResponse<List<ContractTypeEntity>> getAllContractTypes() {
        return SingleResponse.of(contractService.getAllContractTypesTree());
    }


    @GetMapping("/recent")
    @Operation(summary = "获取最近使用的合同类型")
    public SingleResponse<List<ContractTypeEntity>> getRecentContractTypes(
            @RequestParam @Parameter(description = "员工ID", required = true) Long employeeId,
            @RequestParam(required = false, defaultValue = "5")
            @Parameter(description = "返回数量") int limit) {
        return SingleResponse.of(contractService.getRecentContractTypes(employeeId, limit));
    }

    /**
     * 获取合同状态字典
     * @return 合同状态字典列表
     */
    @GetMapping("/status/dict")
    @Operation(summary = "获取合同状态字典")
    public SingleResponse<List<Map<String, Object>>> getContractStatusDict() {
        List<Map<String, Object>> statusList = new ArrayList<>();
        for (ContractStatusEnum status : ContractStatusEnum.values()) {
            // 过滤掉审核中状态
            if ("IN_NEGOTIATION".equals(status.getCode())) {
                continue;
            }
            Map<String, Object> statusMap = new HashMap<>();
            statusMap.put("code", status.getCode());
            statusMap.put("name", status.getMsg());
            statusList.add(statusMap);
        }
        return SingleResponse.of(statusList);
    }

    /**
     * 根据合同ID查询审批实例信息
     * @param contractId 合同ID
     * @return 审批实例信息（包含流程实例ID、当前任务ID、下一个节点assigneeMap、processForm等）
     */
    @Operation(summary = "根据合同ID查询审批实例信息")
    @GetMapping("/approval/instance/{contractId}")
    public SingleResponse<Map<String, Object>> getApprovalInstance(@PathVariable Integer contractId) {
        Map<String, Object> result = new HashMap<>();

        // 查询合同信息
        ContractEntity contract = contractService.getById(contractId);
        if (contract == null) {
            log.warn("合同不存在，合同ID: {}", contractId);
            return SingleResponse.of(result);
        }

        if (contract.getApprovalInstanceId() == null) {
            log.info("合同未启动审批流程，合同ID: {}", contractId);
            result.put("message", "合同未启动审批流程");
            return SingleResponse.of(result);
        }

        result.put("contractId", contractId);
        result.put("approvalProcessId", contract.getApprovalProcessId());
        result.put("processInstanceId", contract.getApprovalInstanceId());
        result.put("currentStatus", contract.getCurrentStatus());

        // 获取当前用户信息
        UserSession userSession = UserSession.getLoginInfo();
        boolean shouldIncludeTaskInfo = false;

        if (userSession != null && userSession.getId() != null) {
            // 检查当前用户是否在审批列表中
            shouldIncludeTaskInfo = checkCurrentUserApprovalPermission(userSession.getId(), contract.getApprovalInstanceId());
        }

        // 获取审批流程相关信息
        if (contract.getApprovalInstanceId() != null) {
            try {
                // 检查流程是否已经结束
                FlwInstance currentInstance = flowLongEngine.queryService().getInstance(contract.getApprovalInstanceId());
                FlwHisInstance historyInstance = flowLongEngine.queryService().getHistInstance(contract.getApprovalInstanceId());
                boolean isProcessActive = currentInstance != null;
                result.put("isProcessActive", isProcessActive);

                // 添加流程实例状态 - 从历史实例获取，因为FlwInstance没有instanceState字段
                if (historyInstance != null) {
                    result.put("instanceState", historyInstance.getInstanceState());
                }

                // 用于传递给approvalInfo的taskId
                Long taskIdForApprovalInfo = null;

                if (isProcessActive) {
                    // 流程还在进行中，获取下一个节点信息
                    // 创建NextNodesDTO
                    NextNodesDTO nextNodesDTO = new NextNodesDTO();
                    nextNodesDTO.setInstanceId(contract.getApprovalInstanceId());

                    // 获取下一个节点的assigneeMap
                    Map<String, Object> nextNodesInfo = flwProcessTaskService.listNextNodesAssigneeMap(nextNodesDTO);
                    if (nextNodesInfo != null) {
                        result.put("nextNodeType", nextNodesInfo.get("nodeType"));
                        result.put("assigneeMap", nextNodesInfo.get("assigneeMap"));
                        result.put("nextNodeCount", nextNodesInfo.get("nodeCount"));
                    }

                    // 获取当前活跃任务
                    List<FlwTask> activeTasks = flowLongEngine.queryService().getTasksByInstanceId(contract.getApprovalInstanceId());
                    if (activeTasks != null && !activeTasks.isEmpty()) {
                        // 保存taskId用于调用approvalInfo，无论当前用户是否有审批权限
                        taskIdForApprovalInfo = activeTasks.get(0).getId();

                        // 只有轮到当前用户审批时才返回任务ID相关信息到result中
                        if (shouldIncludeTaskInfo) {
                            // 返回第一个活跃任务的ID作为下一个需要执行的taskId
                            result.put("taskId", activeTasks.get(0).getId());
                            result.put("nextTaskKey", activeTasks.get(0).getTaskKey());
                            result.put("nextTaskName", activeTasks.get(0).getTaskName());
                            result.put("taskType", activeTasks.get(0).getTaskType()); // 添加节点类型

                            // 如果有多个任务，返回所有任务信息
                            if (activeTasks.size() > 1) {
                                List<Map<String, Object>> allTasks = new ArrayList<>();
                                for (FlwTask task : activeTasks) {
                                    Map<String, Object> taskMap = new HashMap<>();
                                    taskMap.put("taskId", task.getId());
                                    taskMap.put("taskKey", task.getTaskKey());
                                    taskMap.put("taskName", task.getTaskName());
                                    taskMap.put("taskType", task.getTaskType()); // 添加节点类型
                                    allTasks.add(taskMap);
                                }
                                result.put("allActiveTasks", allTasks);
                            }
                        } else {
                            log.info("用户 {} 不在当前任务审批列表中，不返回task相关信息，合同ID: {}", userSession.getId(), contractId);
                        }
                    }
                } else {
                    // 流程已经结束，从历史记录中获取信息
                    if (historyInstance != null) {
                        result.put("processEndTime", historyInstance.getEndTime());
                        result.put("processStatus", "COMPLETED");
                    }

                    // 对于已结束的流程，不再查询活跃任务，但仍返回基本信息
                    result.put("processStatus", "COMPLETED");
                    result.put("message", "审批流程已结束");
                }

                // 获取processForm（无论流程是否结束都可以获取）
                FlwProcessForm processForm = flwProcessFormService.getByInstanceId(contract.getApprovalInstanceId());
                if (processForm != null) {
                    result.put("processForm", processForm.getContent());
                }

                // 调用审批信息接口获取processApprovals和modelContent
                try {
                    ProcessInfoDTO processInfoDTO = new ProcessInfoDTO();
                    processInfoDTO.setInstanceId(contract.getApprovalInstanceId());
                    // 如果有活跃任务，传递taskId；否则为null让approvalInfo方法自动处理
                    if (taskIdForApprovalInfo != null) {
                        processInfoDTO.setTaskId(taskIdForApprovalInfo);
                    }

                    TaskApprovalVO approvalInfo = flwProcessTaskService.approvalInfo(processInfoDTO);
                    if (approvalInfo != null) {
                        result.put("processApprovals", approvalInfo.getProcessApprovals());
                        result.put("modelContent", approvalInfo.getModelContent());
                    }
                } catch (Exception e) {
                    log.error("获取审批信息失败 - 流程实例ID: {}", contract.getApprovalInstanceId(), e);
                }

            } catch (Exception e) {
                log.error("获取审批流程信息失败 - 流程实例ID: {}", contract.getApprovalInstanceId(), e);
                result.put("error", e.getMessage());
            }
        }

        return SingleResponse.of(result);
    }

    /**
     * 检查当前用户是否在当前任务的审批列表中
     * @param userId 用户ID
     * @param approvalInstanceId 审批流程实例ID
     * @return 是否在审批列表中
     */
    private boolean checkCurrentUserApprovalPermission(Long userId, Long approvalInstanceId) {
        try {
            if (approvalInstanceId == null) {
                return false;
            }

            // 获取当前活跃的任务
            List<FlwTask> activeTasks = flowLongEngine.queryService().getTasksByInstanceId(approvalInstanceId);
            if (activeTasks == null || activeTasks.isEmpty()) {
                return false;
            }

            // 检查用户是否有权限操作任何一个活跃任务
            for (FlwTask task : activeTasks) {
                // 获取任务的参与者
                var taskActorsOpt = flowLongEngine.queryService().getActiveTaskActorsByTaskId(task.getId());
                if (taskActorsOpt.isPresent()) {
                    List<FlwTaskActor> taskActors = taskActorsOpt.get();

                    // 使用FlowTaskAccessStrategy检查用户权限
                    FlowTaskAccessStrategy accessStrategy = new FlowTaskAccessStrategy();
                    FlwTaskActor allowedActor = accessStrategy.isAllowed(userId.toString(), taskActors);

                    if (allowedActor != null) {
                        log.info("用户 {} 有权限操作任务 {}", userId, task.getId());
                        return true;
                    }
                }
            }

            log.info("用户 {} 没有权限操作当前流程的任务", userId);
            return false;

        } catch (Exception e) {
            log.error("检查审批权限失败 - 用户ID: {}, 流程实例ID: {}", userId, approvalInstanceId, e);
            return false;
        }
    }

    /**
     * 获取我的合同和协商数量统计
     * @return 我的合同和协商数量统计
     */
    @GetMapping("/count/my-summary")
    @Operation(summary = "获取我的合同和协商数量统计")
    public SingleResponse<ContractCountDTO> getMyContractAndNegotiationCount() {
        UserSession userSession = UserSession.getLoginInfo();
        if (userSession == null || userSession.getId() == null) {
            throw new RuntimeException("用户未登录");
        }

        ContractCountDTO countDTO = contractService.getMyContractAndNegotiationCount(userSession.getId());
        return SingleResponse.of(countDTO);
    }

    /**
     * 查询我的合同（分类查询：我申请的、已审批、待审批）
     * @param dto 查询请求参数
     * @return 我的合同列表
     */
    @PostMapping("/my-contracts")
    @Operation(summary = "查询我的合同（分类查询：我申请的、已审批、待审批）")
    public SingleResponse<Page<ContractDTO>> getMyContracts(@RequestBody MyContractQueryDTO dto) {
        UserSession userSession = UserSession.getLoginInfo();
        if (userSession == null || userSession.getId() == null) {
            throw new RuntimeException("用户未登录");
        }

        Page<ContractDTO> contractList = contractService.getMyContracts(dto, userSession.getId());
        return SingleResponse.of(contractList);
    }

    /**
     * 确认合同附件
     * @param dto 确认请求参数
     * @return 确认结果
     */
    @PostMapping("/attachment/confirm")
    @Operation(summary = "确认合同附件")
    public SingleResponse<Boolean> confirmContractAttachment(@RequestBody @Validated ContractAttachmentConfirmReqDTO dto) {
        boolean result = contractService.confirmContractAttachment(dto.getContractId(), dto.getFileId());
        return SingleResponse.of(result);
    }

    /**
     * 检查当前用户是否已确认所有合同附件
     * @param dto 检查请求参数
     * @return 是否已确认所有附件
     */
    @PostMapping("/attachment/check")
    @Operation(summary = "检查当前用户是否已确认所有合同附件")
    public SingleResponse<Boolean> checkAllAttachmentsConfirmed(@RequestBody @Validated ContractAttachmentCheckReqDTO dto) {
        boolean result = contractService.checkAllAttachmentsConfirmed(dto.getContractId());
        // 明确指定返回成功状态码，因为这是查询操作，false只是表示还有未确认的附件
        return SingleResponse.of(result, 200, result ? "所有附件已确认" : "存在未确认的附件");
    }

    /**
     * 发送"我改完了"通知
     * @param dto 修改完成通知请求参数
     * @return 发送结果
     */
    @PostMapping("/modification-complete")
    @Operation(summary = "发送合同修改完成通知")
    public SingleResponse<Boolean> sendModificationCompleteNotification(@RequestBody @Validated ContractModifiedNotifyReqDTO dto) {
        boolean result = contractService.sendModificationCompleteNotification(dto.getContractId());
        return SingleResponse.of(result);
    }

    /**
     * 查询交易方与我方签订的合同数量
     * @param dto
     * @return
     */
    @Operation(summary = "查询交易方与我方签订的合同数量与交易方具体信息")
    @PostMapping("/counterparty")
    public SingleResponse<CounterpartyContractStatusVO> getCounterpartyContractStatus(@RequestBody QueryCounterpartyContractDTO dto) {
        return contractService.getCounterpartyContractStatus(dto);
    }


    @Operation(summary = "查询交易方与我方签订的合同")
    @PostMapping("/counterparty/single")
    public SingleResponse<List<CounterpartyContractVO>> getSingleCounterpartyContracts(@RequestBody QueryCounterpartyContractDTO dto) {
        return contractService.getSingleCounterpartyContracts(dto);
    }

    @PostMapping("/counterparty/peding")
    @Operation(summary = "查询交易方与我方签订的待签合同")
    public SingleResponse<List<CounterpartyContractVO>> getPendingCounterpartyContracts(@RequestBody QueryCounterpartyContractDTO dto) {
        return contractService.getPendingCounterpartyContracts(dto);
    }

    @GetMapping("/is-backdated/{contractId}")
    @Operation(summary = "判断是否为倒签合同", description = "根据合同ID判断是否为倒签合同，倒签合同的标准是申请时间小于创建时间")
    public SingleResponse<Boolean> isBackdatedContract(
            @Parameter(description = "合同ID", required = true)
            @PathVariable Integer contractId) {
        try {
            log.info("开始判断合同是否为倒签合同，合同ID: {}", contractId);

            Boolean isBackdated = contractService.isBackdatedContract(contractId);

            log.info("判断倒签合同完成，合同ID: {}, 是否倒签: {}", contractId, isBackdated);
            // 使用 of(data, code, message) 方法强制设置成功状态码 200
            return SingleResponse.of(isBackdated, 200, "成功");

        } catch (Exception e) {
            log.error("判断倒签合同异常，合同ID: {}", contractId, e);
            return SingleResponse.failure(500, "判断倒签合同失败: " + e.getMessage());
        }
    }

    @PostMapping("/simple-list")
    @Operation(summary = "获取简化合同列表", description = "支持模糊搜索的简化合同列表，返回基本信息")
    public SingleResponse<Page<ContractSimpleListVO>> getSimpleContractList(@RequestBody ContractSimpleListReqDTO request) {
        try {
            log.info("开始查询简化合同列表，请求参数: {}", request);

            Page<ContractSimpleListVO> result = contractService.getSimpleContractList(request);

            log.info("简化合同列表查询完成，返回 {} 条记录", result.getRecords().size());
            return SingleResponse.of(result);

        } catch (Exception e) {
            log.error("查询简化合同列表异常", e);
            return SingleResponse.failure(-1, "查询合同列表失败: " + e.getMessage());
        }
    }

    @GetMapping("/can-download-word/{fileId}")
    @Operation(summary = "判断是否可以下载Word文件", description = "判断当前用户是否为管理员且文件为Word文档（.doc/.docx）格式")
    public SingleResponse<Boolean> canDownloadWord(
            @Parameter(description = "文件ID", required = true)
            @PathVariable String fileId) {
        try {
            log.info("开始判断是否可以下载Word文件，文件ID: {}", fileId);
            
            Boolean result = contractService.canDownloadWord(fileId);
            
            log.info("判断Word文件下载权限完成，文件ID: {}, 结果: {}", fileId, result);
            // 无论结果是true还是false，都返回200状态码
            return SingleResponse.of(result, 200, "成功");

        } catch (Exception e) {
            log.error("判断Word文件下载权限异常，文件ID: {}", fileId, e);
            // 异常时返回false，但状态码仍为200
            return SingleResponse.of(false, 200, "判断下载权限失败: " + e.getMessage());
        }
    }

    /**
     * 异步导出合同数据
     * @param dto 导出请求参数
     * @return 导出任务启动结果
     */
    @Operation(summary = "异步导出合同数据", description = "根据合同ID数组和字段ID数组导出Excel文件")
    @PostMapping("/export")
    @Logging(logType = LogTypeEnum.CONTRACT_EXPORT)
    public SingleResponse<Boolean> exportContracts(
            @RequestBody 
            @Parameter(description = "导出请求参数", required = true) 
            @Validated ContractExportReqDTO dto) {
        
        log.info("收到合同导出请求，合同数量：{}，字段数量：{}", 
                dto.getContractIds().size(), dto.getFieldIds().size());
        
        try {
            Boolean result = contractExportService.exportContractsAsync(dto);
            
            if (result) {
                return SingleResponse.of(true);
            } else {
                return SingleResponse.failure(500, "启动导出任务失败，请重试");
            }
            
        } catch (Exception e) {
            log.error("合同导出接口异常", e);
            return SingleResponse.failure(500, "导出失败：" + e.getMessage());
        }
    }
}
